{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# docker-stacks wiki webhook\n",
    "\n",
    "Listens for webhook callbacks from Docker Hub. Updates the [docker build history](https://github.com/jupyter/docker-stacks/wiki/Docker-build-history) wiki page in response to completed builds.\n",
    "\n",
    "References:\n",
    "\n",
    "* https://docs.docker.com/docker-hub/webhooks/\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import json\n",
    "import datetime as dt\n",
    "import requests\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read credentials from the environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "GH_USERNAME = os.getenv('GH_USERNAME')\n",
    "GH_TOKEN = os.getenv('GH_TOKEN')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Configure git upfront."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "git config --global user.email \"jupyter@googlegroups.com\"\n",
    "git config --global user.name \"Jupyter Development Team\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Build the templates we need."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "wiki_git_tmpl = 'https://{GH_USERNAME}:{GH_TOKEN}@github.com/jupyter/docker-stacks.wiki.git'\n",
    "commit_url_tmpl = 'https://github.com/jupyter/docker-stacks/commit/{sha}'\n",
    "row_tmpl = '|{pushed_at}|[{sha}]({commit_url})|{commit_msg}|\\n'\n",
    "api_commit_url_tmpl = 'https://api.github.com/repos/jupyter/docker-stacks/commits/{sha}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "REQUEST = json.dumps({\n",
    "    'body' : {\n",
    "       \"push_data\": {\n",
    "          \"pushed_at\": 1449017033,\n",
    "          \"images\": [],\n",
    "          \"tag\": \"9f9907cf1df8\",\n",
    "          \"pusher\": \"biscarch\"\n",
    "       },\n",
    "       \"callback_url\": \"https://registry.hub.docker.com/u/biscarch/webhook-tester-repo/hook/2i5e3gj1bi354asb3f05gchi4ccjg0gas/\",\n",
    "       \"repository\": {\n",
    "          \"status\": \"Active\",\n",
    "          \"description\": \"\",\n",
    "          \"is_trusted\": False,\n",
    "          \"full_description\": None,\n",
    "          \"repo_url\": \"https://registry.hub.docker.com/u/biscarch/webhook-tester-repo/\",\n",
    "          \"owner\": \"biscarch\",\n",
    "          \"is_official\": False,\n",
    "          \"is_private\": False,\n",
    "          \"name\": \"webhook-tester-repo\",\n",
    "          \"namespace\": \"biscarch\",\n",
    "          \"star_count\": 0,\n",
    "          \"comment_count\": 0,\n",
    "          \"date_created\": 1449016916,\n",
    "          \"repo_name\": \"biscarch/webhook-tester-repo\"\n",
    "       }\n",
    "    }\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read values we need out of the request body."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "body = json.loads(REQUEST)['body']\n",
    "\n",
    "tag = body['push_data']['tag']\n",
    "pushed_at_ts = body['push_data']['pushed_at']\n",
    "callback_url = body['callback_url']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Validate the request by seeing if the tag is a valid SHA in the docker-stacks repo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "commit_resp = requests.get(api_commit_url_tmpl.format(sha=tag))\n",
    "try:\n",
    "    commit_resp.raise_for_status()\n",
    "except Exception as ex:\n",
    "    requests.post(callback_url, json={\n",
    "        'state': 'failure',\n",
    "        'description': 'request does not contain a valid sha',\n",
    "        'context' : 'docker-stacks-webhook',\n",
    "        'target_url' : 'https://github.com/jupyter/docker-stacks/wiki/Docker-build-history'\n",
    "    })\n",
    "    raise ex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get a fresh clone of the wiki git repo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "wiki_git = wiki_git_tmpl.format(GH_USERNAME=GH_USERNAME, GH_TOKEN=GH_TOKEN)\n",
    "\n",
    "!rm -rf docker-stacks.wiki\n",
    "!git clone $wiki_git"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read the build page markdown."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "with open('docker-stacks.wiki/Docker-build-history.md') as f:\n",
    "    lines = f.readlines()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Find the start of the table."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "for table_top_i, line in enumerate(lines):\n",
    "    if line.startswith('|--'):\n",
    "        break\n",
    "else:\n",
    "    requests.post(callback_url, json={\n",
    "        'state': 'failure',\n",
    "        'description': 'could not locate table on wiki page',\n",
    "        'context' : 'docker-stacks-webhook',\n",
    "        'target_url' : 'https://github.com/jupyter/docker-stacks/wiki/Docker-build-history'\n",
    "    })\n",
    "    raise RuntimeError('wiki table missing')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Format the text we want to put into the wiki table row."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "pushed_at_dt = dt.datetime.fromtimestamp(pushed_at_ts)\n",
    "pushed_at = pushed_at_dt.strftime('%b. %d, %Y')\n",
    "commit_url = commit_url_tmpl.format(sha=tag)\n",
    "commit_msg = commit_resp.json()['commit']['message'].replace('\\n', ' ')\n",
    "row = row_tmpl.format(pushed_at=pushed_at, sha=tag, commit_url=commit_url, commit_msg=commit_msg)\n",
    "row"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Insert the table row."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "lines.insert(table_top_i+1, row)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Write the file back out."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "with open('docker-stacks.wiki/Docker-build-history.md', 'w') as f:\n",
    "    f.writelines(lines)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Commit and push."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "!cd docker-stacks.wiki/ && \\\n",
    "    git add -A && \\\n",
    "    git commit -m 'Add build $tag' && \\\n",
    "    git push origin master"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tell Docker Hub we succeeded."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# POST /tag\n",
    "resp = requests.post(callback_url, json={\n",
    "    'state': 'success',\n",
    "    'description': 'updated docker-stacks wiki build page',\n",
    "    'context' : 'docker-stacks-webhook',\n",
    "    'target_url' : 'https://github.com/jupyter/docker-stacks/wiki/Docker-build-history'\n",
    "})\n",
    "\n",
    "print(resp.status_code)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
